<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>P2P 桌面共享</title>
    <script src="/socket.io/socket.io.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.2);
        }
        .header {
            text-align: center;
            margin-bottom: 30px;
        }
        .controls {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
            flex-wrap: wrap;
        }
        .btn {
            padding: 10px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            transition: all 0.3s;
        }
        .btn-primary { background: #007bff; color: white; }
        .btn-success { background: #28a745; color: white; }
        .btn-danger { background: #dc3545; color: white; }
        .btn:hover { transform: translateY(-2px); }
        input {
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 16px;
            flex: 1;
        }
        .status {
            padding: 10px;
            border-radius: 5px;
            margin-bottom: 20px;
            font-weight: bold;
        }
        .status.connected { background: #d4edda; color: #155724; }
        .status.disconnected { background: #f8d7da; color: #721c24; }
        .video-container {
            background: #000;
            border-radius: 10px;
            overflow: hidden;
            margin-top: 20px;
        }
        video {
            width: 100%;
            height: auto;
            display: block;
        }
        .hidden { display: none; }
        .video-container video {
            cursor: pointer;
            transition: box-shadow 0.3s;
        }
        .video-container video:focus {
            outline: none;
            box-shadow: 0 0 0 4px #007bff;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🖥️ P2P 桌面共享</h1>
            <p>基于 WebRTC 的实时屏幕共享</p>
        </div>

        <div id="status" class="status disconnected">🔴 未连接</div>

        <div class="controls">
            <input type="text" id="roomId" placeholder="输入房间ID" value="room123">
            <button class="btn btn-primary" onclick="joinRoom()">加入房间</button>
            <button class="btn btn-success" onclick="startShare()">开始共享</button>
            <button class="btn btn-danger" onclick="stopShare()">停止共享</button>
        </div>

        <div id="videoContainer" class="video-container hidden">
            <video id="localVideo" autoplay muted playsinline onclick="requestFullscreen(this)"></video>
        </div>
        <div id="remoteVideos" class="video-container"></div>
    </div>

    <script>
        let socket;
        let localStream;
        let roomId = '';
        let peers = {}; // 保存所有peerConnection

        document.addEventListener('DOMContentLoaded', function() {
            socket = io();
            
            socket.on('connect', () => {
                updateStatus('connected', '🟢 已连接到服务器');
            });

            socket.on('disconnect', () => {
                updateStatus('disconnected', '🔴 与服务器断开连接');
            });

            // 新用户加入
            socket.on('user-joined', (userId) => {
                if (userId !== socket.id) {
                    createPeerConnection(userId, true);
                }
            });

            // 房间内现有用户
            socket.on('room-users', (users) => {
                users.forEach(userId => {
                    if (userId !== socket.id) {
                        createPeerConnection(userId, false);
                    }
                });
            });

            // offer信令
            socket.on('offer', async (data) => {
                const { from, offer } = data;
                if (!peers[from]) {
                    createPeerConnection(from, false);
                }
                await peers[from].setRemoteDescription(new RTCSessionDescription(offer));
                const answer = await peers[from].createAnswer();
                await peers[from].setLocalDescription(answer);
                socket.emit('answer', { target: from, answer });
            });

            // answer信令
            socket.on('answer', async (data) => {
                const { from, answer } = data;
                if (peers[from]) {
                    await peers[from].setRemoteDescription(new RTCSessionDescription(answer));
                }
            });

            // ICE候选
            socket.on('ice-candidate', async (data) => {
                const { from, candidate } = data;
                if (peers[from]) {
                    try {
                        await peers[from].addIceCandidate(new RTCIceCandidate(candidate));
                    } catch (e) { console.error(e); }
                }
            });

            // 用户离开
            socket.on('user-left', (userId) => {
                removeRemoteVideo(userId);
                if (peers[userId]) {
                    peers[userId].close();
                    delete peers[userId];
                }
            });
        });

        function updateStatus(type, message) {
            const statusEl = document.getElementById('status');
            statusEl.className = `status ${type}`;
            statusEl.textContent = message;
        }

        function joinRoom() {
            roomId = document.getElementById('roomId').value.trim();
            if (!roomId) {
                alert('请输入房间ID');
                return;
            }
            socket.emit('join-room', roomId);
            updateStatus('connected', `🟢 已加入房间: ${roomId}`);
        }

        async function startShare() {
            try {
                // 优先提示用户选择窗口而非全屏以降低延迟
                alert('建议选择“窗口”而不是“全屏”进行共享，以获得更低延迟');
                localStream = await navigator.mediaDevices.getDisplayMedia({
                    video: {
                        cursor: 'always',
                        width: { max: 960 },
                        height: { max: 540 },
                        frameRate: { max: 10 }
                    },
                    audio: false
                });

                const localVideo = document.getElementById('localVideo');
                localVideo.srcObject = localStream;
                document.getElementById('videoContainer').classList.remove('hidden');

                updateStatus('connected', '📺 正在共享屏幕');

                localStream.getVideoTracks()[0].onended = () => {
                    stopShare();
                };

                // 通知所有peer添加本地流
                for (const peerId in peers) {
                    localStream.getTracks().forEach(track => {
                        peers[peerId].addTrack(track, localStream);
                    });
                }

            } catch (error) {
                console.error('获取屏幕共享失败:', error);
                alert('无法获取屏幕共享权限');
            }
        }

        function stopShare() {
            if (localStream) {
                localStream.getTracks().forEach(track => track.stop());
                localStream = null;
            }
            document.getElementById('localVideo').srcObject = null;
            document.getElementById('videoContainer').classList.add('hidden');
            updateStatus('connected', `🟢 已加入房间: ${roomId}`);
        }

        function createPeerConnection(peerId, isInitiator) {
            if (peers[peerId]) return;
            const pc = new RTCPeerConnection({
                iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
            });
            peers[peerId] = pc;

            // 本地流加入
            if (localStream) {
                localStream.getTracks().forEach(track => {
                    const sender = pc.addTrack(track, localStream);
                    // 设置最大码率 300kbps
                    if (sender && sender.getParameters) {
                        const params = sender.getParameters();
                        if (!params.encodings) params.encodings = [{}];
                        params.encodings[0].maxBitrate = 300 * 1000;
                        sender.setParameters(params).catch(e => {});
                    }
                });
            }

            // 远端流
            pc.ontrack = (event) => {
                addRemoteVideo(peerId, event.streams[0]);
            };

            // ICE
            pc.onicecandidate = (event) => {
                if (event.candidate) {
                    socket.emit('ice-candidate', { target: peerId, candidate: event.candidate });
                }
            };

            // 发起连接
            if (isInitiator) {
                pc.onnegotiationneeded = async () => {
                    try {
                        const offer = await pc.createOffer();
                        await pc.setLocalDescription(offer);
                        socket.emit('offer', { target: peerId, offer });
                    } catch (e) { console.error(e); }
                };
            }
        }

        function requestFullscreen(videoEl) {
            if (videoEl.requestFullscreen) {
                videoEl.requestFullscreen();
            } else if (videoEl.webkitRequestFullscreen) {
                videoEl.webkitRequestFullscreen();
            } else if (videoEl.mozRequestFullScreen) {
                videoEl.mozRequestFullScreen();
            } else if (videoEl.msRequestFullscreen) {
                videoEl.msRequestFullscreen();
            }
        }

        function addRemoteVideo(peerId, stream) {
            let video = document.getElementById('remote_' + peerId);
            if (!video) {
                video = document.createElement('video');
                video.id = 'remote_' + peerId;
                video.autoplay = true;
                video.playsInline = true;
                video.style.marginTop = '10px';
                video.onclick = function() { requestFullscreen(video); };
                document.getElementById('remoteVideos').appendChild(video);
            }
            video.srcObject = stream;
        }

        function removeRemoteVideo(peerId) {
            const video = document.getElementById('remote_' + peerId);
            if (video) {
                video.parentNode.removeChild(video);
            }
        }
    </script>
</body>
</html>